//
//  RZSocketRocketManager.m
//  Water
//
//  Created by reyzhang on 2021/7/13.
//

#import "RZSocketRocketManager.h"
#import <MJExtension/MJExtension.h>


static void dispatch_main_async_safe(dispatch_block_t block) {
    if ([NSThread isMainThread]) {
        block();
    }
    else {
        dispatch_async(dispatch_get_main_queue(), block);
    }
}

//用户在其他地方登录
RZSocketResponseType const RZSocketResponseTypeOtherLogin = @"21";
//服务器断开连接
RZSocketResponseType const RZSocketResponseTypeServerDisconnect = @"22";



NSString * const RZNotification_SocketRocketDidOpen = @"RZNotification_SocketRocketDidOpen";
NSString * const RZNotification_SocketRocketDidOpenFailure = @"RZNotification_SocketRocketDidOpenFailure";
NSString * const RZNotification_SocketRocketDidClose = @"RZNotification_SocketRocketDidClose";
NSString * const RZNotification_SocketRocketDidReceive = @"RZNotification_SocketRocketDidReceive";


@interface RZSocketRocketManager ()<SRWebSocketDelegate>

@property (nonatomic,strong) SRWebSocket *socket;

@property (nonatomic,strong) NSTimer *heartBeat;

@property (nonatomic,assign) NSTimeInterval reConnectTime;

@property (nonatomic,copy) NSString *urlString;

@property (nonatomic, strong) NSString *token;

@property (nonatomic, strong) NSOperationQueue *messageQueue;

@end

@implementation RZSocketRocketManager

+ (instancetype)shareInstance {
    static RZSocketRocketManager *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[RZSocketRocketManager alloc] init];
    });
    return instance;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.needReConnect = YES;
        self.messageQueue = [[NSOperationQueue alloc] init];
        self.messageQueue.maxConcurrentOperationCount = 1;
        self.messageQueue.name = @"im.reyzhang.sendMessageQueue";
    }
    return self;
}

- (void)openWithURLString:(NSString *)urlString token:(NSString *)token {
    if (self.socket) {
        return;
    }
    if (!urlString) {
        return;
    }
    self.urlString = urlString;
    self.token = token;
    
    NSURL *url = [NSURL URLWithString:urlString];
    if (!url) {
        return;
    }
    
    /**
     token鉴权 rey
     */
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    if (token.length > 0) {
        [request setValue:token forHTTPHeaderField:@"Sec-WebSocket-Protocol"];
    }
    [self openWithURLRequest:request];
}

- (void)openWithURLRequest:(NSURLRequest *)request {
    if (self.socket) {
        return;
    }
    
    if (!request) {
        return;
    }
    
    self.urlString = request.URL.absoluteString;
    self.socket = [[SRWebSocket alloc] initWithURLRequest:request];
    
    self.socket.delegate = self;
    [self.socket open];
}




- (void)close {
    if (self.socket){
        [self.socket close];
//        self.socket = nil;
//        self.socket.delegate = nil;
        [self destoryHeartBeat];
    }
}

- (void)sendData:(id)data {
    dispatch_main_async_safe(^{
        if (self.socket != nil) {
            // 只有 SR_OPEN 开启状态才能调 send 方法啊，不然要崩
            if (self.socket.readyState == SR_OPEN) {
                [self.socket send:data];    // 发送数据
                
            } else if (self.socket.readyState == SR_CONNECTING) {
                NSLog(@"正在连接中");
                [self reConnect];
            } else if (self.socket.readyState == SR_CLOSING || self.socket.readyState == SR_CLOSED) {
                [self reConnect];
            }
        }
    });
}

/** 发送消息 */
- (void)sendMesage:(RZMessage *)message {
    //在队列中进行消息的添加
    [self.messageQueue addOperationWithBlock:^{
        NSString *jsonStr = message.mj_JSONString;
        [self sendData:jsonStr];
    }];
}


//重连机制
- (void)reConnect {
    dispatch_main_async_safe(^{
        if (!self.needReConnect) {
            return;
        }
        
        NSLog(@"重连时，主动关闭socket连接");
        [self close];

        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.reConnectTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            self.socket = nil;
            [self openWithURLString:self.urlString token:self.token];
        });
        
        if (self.reConnectTime == 0) {
            self.reConnectTime = 2; //设置每2秒重连一次
        }
    });
}

//取消心跳
- (void)destoryHeartBeat {
    if (self.heartBeat) {
        if ([self.heartBeat respondsToSelector:@selector(isValid)]){
            if ([self.heartBeat isValid]){
                [self.heartBeat invalidate];
                self.heartBeat = nil;
            }
        }
    }
}

//初始化心跳
- (void)initHeartBeat {
    [self destoryHeartBeat];
    self.heartBeat = [NSTimer timerWithTimeInterval:60 target:self selector:@selector(sentheart) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:self.heartBeat forMode:NSRunLoopCommonModes];
}

-(void)sentheart {
    dispatch_main_async_safe(^{
        //发送心跳
        [self sendData:@"1"];
        NSLog(@"发送心跳");
    });
}

#pragma mark - delegate
- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
    dispatch_main_async_safe(^{
        //每次正常连接的时候清零重连时间
        self.reConnectTime = 0;
        //开启心跳
        [self initHeartBeat];
        if (webSocket == self.socket) {
            NSLog(@"socket连接成功");
            [[NSNotificationCenter defaultCenter] postNotificationName:RZNotification_SocketRocketDidOpen object:nil];
        }
    });
}

- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
    dispatch_main_async_safe(^{
        if (webSocket == self.socket) {
            NSLog(@"socket连接失败");
            [[NSNotificationCenter defaultCenter] postNotificationName:RZNotification_SocketRocketDidOpenFailure object:error];
            self->_socket = nil;
            [self reConnect];
        }
    });
}

- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
    dispatch_main_async_safe(^{
        if (webSocket == self.socket) {
            NSLog(@"socket连接断开 被关闭连接，code:%ld,reason:%@,wasClean:%d",(long)code,reason,wasClean);
            [[NSNotificationCenter defaultCenter] postNotificationName:RZNotification_SocketRocketDidClose object:nil];
            self.socket = nil;
            self.socket.delegate = nil;
            [self destoryHeartBeat];
        }
    });
    
}

/*该函数是接收服务器发送的pong消息，其中最后一个是接受pong消息的，
 在这里就要提一下心跳包，一般情况下建立长连接都会建立一个心跳包，
 用于每隔一段时间通知一次服务端，客户端还是在线，这个心跳包其实就是一个ping消息，
 */
- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload {
//    NSString *reply = [[NSString alloc] initWithData:pongPayload encoding:NSUTF8StringEncoding];
    
}

- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
    dispatch_main_async_safe(^{
        if (webSocket == self.socket) {
            NSLog(@"socket收到数据message:%@",message);
            RZMessage *msgInfo = [RZMessage mj_objectWithKeyValues:message];
            if (msgInfo) {
                
                if (msgInfo.message.msgType == MessageType_SYS_OTHERLOGIN ) { //断开连接，并提示
                    [self close];
                }else if (msgInfo.message.msgType == MessageType_SYS_SERVERDISCONNECT) { //服务器断开连接， 去重连
                    [self reConnect];
                }
                
                [[NSNotificationCenter defaultCenter] postNotificationName:RZNotification_SocketRocketDidReceive object:msgInfo];
            }
        }
    });
    
}

- (SRReadyState)socketReadyState {
    return self.socket.readyState;
}

@end
